﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using XSTDZ.ERP.Application.DataContracts;
using AutoMapper;
using XSTDZ.ERP.Domain.Models;
using XSTDZ.ERP.Core.Repositories;
using XSTDZ.ERP.Core.Generator;
using XSTDZ.ERP.Core.Specifications;

namespace XSTDZ.ERP.Application.Implements
{
    public class ProductAllotServiceImpl : ApplicationServiceBase, IProductAllotService
    {
        IRepository<ProductAllot> _billRepository;
        IRepository<ProductAllotDetail> _billItemRepository;
        IRepository<ReceivablePayableBill> _billReceRepository;
        public ProductAllotServiceImpl(IRepositoryContext repositoryContext,
             IRepository<ProductAllot> billRepository,
            IRepository<ProductAllotDetail> billItemRepository,
            IRepository<ReceivablePayableBill> billReceRepository)
            : base(repositoryContext)
        {
            this._billRepository = billRepository;
            this._billItemRepository = billItemRepository;
            this._billReceRepository = billReceRepository;
        }
        public Guid AddProductAllot(ProductAllotDto productAllotDto)
        {
            var bill = Mapper.Map<ProductAllotDto, ProductAllot>(productAllotDto);
            this._billRepository.Add(bill.Init());
            this.Context.Commit();
            return bill.Id;
        }
        public Guid AddProductAllot(ProductAllotDto productAllotDto, IEnumerable<ProductAllotDetailDto> productAllotDetailDtos)
        {
            if (productAllotDetailDtos == null || productAllotDetailDtos.Count() == 0)
            {
                return AddProductAllot(productAllotDto);
            }

            var bill = Mapper.Map<ProductAllotDto, ProductAllot>(productAllotDto);
            var billItem = Mapper.Map<IEnumerable<ProductAllotDetailDto>, IEnumerable<ProductAllotDetail>>(productAllotDetailDtos);
            bill.Init().AddDetails(billItem);
            this._billRepository.Add(bill);
            this.Context.Commit();
            return bill.Id;
        }
        #region 审核
        //审核
        public void Audit(IList<Guid> billIds, Guid auditId, Guid orgId)
        {
            var pinBills = this._billRepository.GetAll(t => billIds.Contains(t.Id));
           
            var recelst = new List<ReceivablePayableBill>();
            pinBills.Each(t =>
            {
                if (t.BillState != 1)
                {
                    t.UpdateID = auditId;
                    t.BillState = 1;
                    t.UpdateDate = DateTime.Now;
                   // var rpbs = CreateReceivablePayableBill(t, auditId, orgId);
                    var rpbs = CreateReceivablePayableBill(t, auditId, t.AllotOrgID);
                    recelst.Add(rpbs[0]);
                    recelst.Add(rpbs[1]);
                }
            });
            if (recelst != null && recelst.Count > 0)
            {
                ReceivablePayableServiceImpl rb = new ReceivablePayableServiceImpl(this.Context, this._billReceRepository, null);
                rb.CreateReceivablePayable(recelst);
            }
            this._billRepository.Update(pinBills);
            this.Context.Commit();
        }
        //生成收付款账单
        private ReceivablePayableBill[] CreateReceivablePayableBill(ProductAllot sbill, Guid auditId, Guid orgId)
        {
            var billPay = new ReceivablePayableBill();
            billPay.ClientID = sbill.FromClientID;
            billPay.BillClassify = true;//付款
            billPay.BillType = 3;//调拔应付
            billPay.BusinessID = sbill.Id;
            billPay.CreateID = auditId;
            billPay.OrgID = orgId;
            //总应付款
            billPay.BillPayable = sbill.ProductAllotDetail.Where(t => t.Deleted == 0).Select(t => (decimal)((decimal)t.AllotAmount * t.AllotPrice)).Sum();

            var billRec = new ReceivablePayableBill();
            billRec.ClientID = sbill.ToClientID;
            billRec.BillClassify = false;//收款
            billRec.BillType = 2;//调拔应收
            billRec.BusinessID = sbill.Id;
            billRec.CreateID = auditId;
            billRec.OrgID = orgId;
            //总应收款
            billRec.BillReceivable = billPay.BillPayable;
            return new ReceivablePayableBill[]{ billPay, billRec };
        }
        #endregion
        public void UpdateProductAllot(ProductAllotDto productAllotDto)
        {
            var profitAndLossBill = this._billRepository.GetByKey(productAllotDto.Id);
            productAllotDto.CreateTime = profitAndLossBill.CreateTime;
            var targetBill = Mapper.Map(productAllotDto, profitAndLossBill);
            this._billRepository.Update(targetBill);
            this.Context.Commit();
        }

        public void UpdateProductAllot(ProductAllotDto productAllotDto, IEnumerable<ProductAllotDetailDto> productAllotDetailDtos)
        {
            var profitAndLossBill = this._billRepository.GetByKey(productAllotDto.Id);
            productAllotDto.CreateTime = profitAndLossBill.CreateTime;
            productAllotDto.CreateID = profitAndLossBill.CreateID;
            var targetBill = Mapper.Map(productAllotDto, profitAndLossBill);

            //处理明细
            var productCheckBillDetails = Mapper.Map<IEnumerable<ProductAllotDetailDto>, IEnumerable<ProductAllotDetail>>(productAllotDetailDtos);

            var updateItems = new List<ProductAllotDetail>();
            var insertItems = new List<ProductAllotDetail>();
            var itemIds = profitAndLossBill.ProductAllotDetail.Select(d => d.Id).Cast<Guid>();

            productCheckBillDetails.Each(
                pd =>
                {
                    if (itemIds.Contains(pd.Id))
                    {
                        updateItems.Add(pd);
                    }
                    else
                    {
                        insertItems.Add(pd.Init());
                    }
                }
                );
            if (updateItems.Count() != 0)
            {
                foreach (var p in targetBill.ProductAllotDetail)
                {
                    foreach (var m in updateItems)
                    {
                        if (m.Id == p.Id)
                        {
                            //p.StockID = m.StockID;
                            p.ProductID = p.ProductID;
                            p.AllotAmount = m.AllotAmount;
                            p.AllotPrice = m.AllotPrice;
                            p.Remarks = m.Remarks;
                            break;
                        }
                    }
                }

                Mapper.Map(updateItems, targetBill.ProductAllotDetail);
            }
            if (insertItems.Count() != 0)
            {
                this._billItemRepository.Add(insertItems);
            }
            this._billRepository.Update(targetBill);
            this.Context.Commit();
        }

        public void ConvertProductAllotDeleteState(Guid productAllotId)
        {
            var pbill = this._billRepository.GetByKey(productAllotId);
            pbill.Deleted = 1;
            pbill.ProductAllotDetail.Each(d =>
            {
                d.Deleted = 1;
            });
            this._billRepository.Update(pbill);
            this.Context.Commit();
        }

        public void ConvertProductAllotDeleteState(Guid productAllotId, IEnumerable<Guid> productAllotDetailIds)
        {
            var pbill = this._billRepository.GetByKey(productAllotId);
            pbill.Deleted = 1;
            pbill.ProductAllotDetail.Each(d =>
            {
                if (productAllotDetailIds.Contains(d.Id))
                {
                    d.Deleted = 1;
                }
            });
            this._billRepository.Update(pbill);
            this.Context.Commit();
        }

        public ProductAllotDto GetProductAllot(Guid productAllotId)
        {
            var productCheckBill = this._billRepository.GetByKey(productAllotId);
            //if (productCheckBill.Checkor == null) { productCheckBill.Checkor = new User(); };
            //productCheckBill.Affirmor = productCheckBill.Affirmor ?? new User();
            //productCheckBill.Sender = productCheckBill.Sender ?? new User();
            //productCheckBill.Deliveryor = productCheckBill.Deliveryor ?? new User();
            //productCheckBill.Delivery = productCheckBill.Delivery ?? new Dept();
            return Mapper.Map<ProductAllot, ProductAllotDto>(productCheckBill);
        }

        public IEnumerable<ProductAllotDto> GetProductAllots(out int recordCount,int pageIndex, int pageSize)
        {
            //ISpecification<ProductDeliveryBill> spec = Specification<ProductDeliveryBill>.Eval(t => true);
            //if (isDeleted.HasValue)
            //{
            //    int _deleted = isDeleted.Value ? 1 : 0;
            //    spec = spec.And(Specification<ProductDeliveryBill>.Eval(t => t.Deleted == _deleted));
            //}
            //if (isAudited.HasValue)
            //{
            //    int _isAudited = isAudited.Value ? 1 : 0;
            //    spec = spec.And(Specification<ProductDeliveryBill>.Eval(t => t.AffirmState == _isAudited));
            //}
            recordCount=0;

            var orderby = new OrderByParameter<ProductAllot>(m => m.CreateTime, SortOrder.Descending);
            var productCheckBills = this._billRepository.GetAll( pageIndex, pageSize, new[] { orderby });
            //productCheckBills.Each(t =>
            //{
            //    t.Affirmor = t.Affirmor ?? new User();
            //    t.Sender = t.Sender ?? new User();
            //    t.Deliveryor = t.Deliveryor ?? new User();
            //    t.Delivery = t.Delivery ?? new Dept();
            //});
            return Mapper.Map<IEnumerable<ProductAllot>, IEnumerable<ProductAllotDto>>(productCheckBills);
        }

        public void UpdateToStock(Guid productAllotId, IEnumerable<Guid> productAllotDetailIds)
        {
            throw new NotImplementedException();
        }

        public void AddProductAllotDetail(Guid productAllotId, ProductAllotDetailDto productAllotDetailDtos)
        {
            throw new NotImplementedException();
        }

        public void UpdateProductAllotDetail(Guid productAllotId, IEnumerable<ProductAllotDetailDto> productAllotDetailDtos)
        {
            throw new NotImplementedException();
        }

        public ProductAllotDetailDto GetProductAllotDetail(Guid productAllotDetailId)
        {
            throw new NotImplementedException();
        }

        public IEnumerable<ProductAllotDetailDto> GetProductAllotDetails(Guid productAllotDetailId)
        {
            var productCheckBills = this._billItemRepository.GetAll(d => d.ProductAllotID == productAllotDetailId);
            return Mapper.Map<IEnumerable<ProductAllotDetail>, IEnumerable<ProductAllotDetailDto>>(productCheckBills);
        }

        public string GetMaxBillNo()
        {
            var orderby = new OrderByParameter<ProductAllot>(m => m.CreateTime, SortOrder.Descending);
            var billNo = this._billRepository.GetAll(1, 1, new[] { orderby }).FirstOrDefault();
            return billNo==null?"": billNo.AllotNo;
        }
    }

}
